home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / lfs / lfsFileLayout.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  56.5 KB  |  1,894 lines

  1. /* 
  2.  * lfsFileLayout.c --
  3.  *
  4.  *    Control the writing, cleaning, and checkpointing of files and 
  5.  *    file descriptors.
  6.  *
  7.  * Copyright 1989 Regents of the University of California
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/lfs/lfsFileLayout.c,v 1.19 92/06/01 15:07:23 kupfer Exp $ SPRITE (Berkeley)";
  19. #endif /* not lint */
  20.  
  21. #include <lfsInt.h>
  22. #include <lfsSeg.h>
  23. #include <lfsFileLayout.h>
  24. #include <lfsDesc.h>
  25. #include <lfsDescInt.h>
  26.  
  27. #include <fsdm.h>
  28. #include <fscache.h>
  29. #include <rpc.h>
  30. #include <user/time.h>
  31.  
  32. #ifdef TRACING
  33. #include <trace.h>
  34. Trace_Header lfsTraceHdr;
  35. Trace_Header *lfsTraceHdrPtr = &lfsTraceHdr;
  36. int lfsTraceLength = 1000;
  37. typedef struct LfsTraceRecord {
  38.     int    fileNumber;
  39.     LfsDiskAddr diskAddr;
  40.     ReturnStatus status;
  41.     int  curTruncVersion;
  42. } LfsTraceRecord;
  43. #endif
  44.  
  45. #define    LOCKPTR    &lfsPtr->lock
  46.  
  47. Boolean    lfsFileLayoutDebug = FALSE;
  48.  
  49. typedef struct FileSegLayout {
  50.     int     numDescSlotsLeft;    /* Number of slots left in descriptor block. */
  51.     LfsFileDescriptor *descBlockPtr;        
  52.                 /* Pointer to next slot in descriptor block. */
  53.     LfsDiskAddr descDiskAddr;     /* Disk address of descriptor block. */
  54.     int maxElements;          /* The maximum number of elements. */
  55.     List_Links    fileList; /* List of files in this segment. */
  56.     List_Links  blockList; /* List of cache blocks laidout in
  57.                        * this segment.  */
  58.     Fscache_FileInfo    *activeFilePtr;    /* File current being written. */
  59.     List_Links    dirLogListHdr;    /* List of directory block blocks being 
  60.                  * written. */
  61. } FileSegLayout;
  62.  
  63. static Boolean PlaceFileInSegment _ARGS_((Lfs *lfsPtr, LfsSeg *segPtr, 
  64.     Fscache_FileInfo *cacheInfoPtr, LfsFileLayout *layoutPtr, 
  65.     int token, FileSegLayout *segLayoutDataPtr));
  66.  
  67. static Boolean BlockMatch _ARGS_((Fscache_Block *blockPtr, 
  68.                 ClientData clientData));
  69.  
  70. static void DirLogInit _ARGS_((Lfs *lfsPtr));
  71. static void DirLogDestory _ARGS_((Lfs *lfsPtr));
  72. static void NewDirLogBlock _ARGS_((Lfs *lfsPtr));
  73. static LfsDirOpLogEntry *FindLogEntry _ARGS_((Lfs *lfsPtr, int logSeqNum));
  74. /*
  75.  * Last param is for ASPLOS.  Remove when done.  Mary 2/15/92.
  76.  */
  77. static Boolean AddDirLogBlocks _ARGS_((Lfs *lfsPtr, LfsSeg *segPtr, 
  78.             FileSegLayout *segLayoutDataPtr, int currentOp));
  79. static void FreeDirLogBlocks _ARGS_((Lfs *lfsPtr, LfsSeg *segPtr,
  80.             FileSegLayout *segLayoutDataPtr));
  81.  
  82. extern ReturnStatus LfsFileLayoutAttach _ARGS_((Lfs *lfsPtr, 
  83.             int checkPointSize, char *checkPointPtr));
  84. extern Boolean LfsFileLayoutProc _ARGS_((LfsSeg *segPtr, int flags, 
  85.             ClientData *clientDataPtr));
  86. extern Boolean LfsFileLayoutCheckpoint _ARGS_((LfsSeg *segPtr, int flags, 
  87.             char *checkPointPtr, int *checkPointSizePtr, 
  88.             ClientData *clientDataPtr));
  89. extern void LfsFileLayoutWriteDone _ARGS_((LfsSeg *segPtr, int flags, 
  90.             ClientData *clientDataPtr));
  91. extern Boolean LfsFileLayoutClean _ARGS_((LfsSeg *segPtr, int *sizePtr, 
  92.             int *numCacheBlocksPtr, ClientData *clientDataPtr));
  93.  
  94. extern ReturnStatus LfsFileLayoutDetach _ARGS_((Lfs *lfsPtr));
  95.  
  96. static LfsSegIoInterface layoutIoInterface = 
  97.     { LfsFileLayoutAttach, LfsFileLayoutProc, LfsFileLayoutClean,
  98.       LfsFileLayoutCheckpoint, LfsFileLayoutWriteDone, 
  99.       LfsFileLayoutDetach, 0};
  100.  
  101. #define    WRITEBACK_TOKEN        0
  102. #define    CLEANING_TOKEN        1
  103. #define    CHECKPOINT_TOKEN    2
  104.  
  105. /*
  106.  * For ASPLOS stats collecting only.  Get rid of this when that's over.
  107.  * -Mary 2/16/92.
  108.  */
  109. Boolean    Lfs_DoASPLOSStats = TRUE;
  110.  
  111.  
  112. /*
  113.  *----------------------------------------------------------------------
  114.  *
  115.  * LfsFileLayoutInit --
  116.  *
  117.  *    Initialize the call back structure is for LfsFileLayout().  
  118.  *
  119.  * Results:
  120.  *    None
  121.  *    
  122.  * Side effects:
  123.  *
  124.  *----------------------------------------------------------------------
  125.  */
  126.  
  127. void
  128. LfsFileLayoutInit()
  129. {
  130.     LfsSegIoRegister(LFS_FILE_LAYOUT_MOD,&layoutIoInterface);
  131. #ifdef TRACING
  132.     Trace_Init(lfsTraceHdrPtr, lfsTraceLength, sizeof(LfsTraceRecord),
  133.         TRACE_NO_TIMES);
  134. #endif
  135. }
  136.  
  137. #ifdef TRACING
  138. ReturnStatus
  139. Lfs_PrintRec(clientData, event, printHeaderFlag)
  140.     ClientData clientData;    /* Client data in the trace record */
  141.     int event;            /* Type, or event, from the trace record */
  142.     Boolean printHeaderFlag;    /* If TRUE, a header line is printed */
  143. {
  144.     LfsTraceRecord *recPtr = (LfsTraceRecord *) clientData;
  145.     if (recPtr != (LfsTraceRecord *) NIL) { 
  146.     printf("<%d,%d,%d,%d>\n", recPtr->fileNumber, recPtr->blockNumber,
  147.             LfsDiskAddrToOffset(recPtr->diskAddr), recPtr->found);
  148.     }
  149.     return SUCCESS;
  150. }
  151. void
  152. Lfs_PrintTrace(numRecs)
  153.     int numRecs;
  154. {
  155.     if (numRecs < 0) {
  156.     numRecs = lfsTraceLength;
  157.     }
  158.     printf("LFS TRACE\n");
  159.     (void)Trace_Print(lfsTraceHdrPtr, numRecs, Lfs_PrintRec);
  160. }
  161. #endif
  162.  
  163. /*
  164.  *----------------------------------------------------------------------
  165.  *
  166.  * FileLayoutAttach --
  167.  *
  168.  *    Attach routine for file layout module. Creates and initializes the
  169.  *    data structures used for writeback for this file system.
  170.  *
  171.  * Results:
  172.  *    SUCCESS if attaching is going ok.
  173.  *
  174.  * Side effects:
  175.  *    Many
  176.  *
  177.  *----------------------------------------------------------------------
  178.  */
  179. /*ARGSUSED*/
  180. ReturnStatus
  181. LfsFileLayoutAttach(lfsPtr, checkPointSize, checkPointPtr)
  182.     Lfs   *lfsPtr;         /* File system for attach. */
  183.     int   checkPointSize;    /* Size of checkpoint data. */
  184.     char  *checkPointPtr;     /* Data from last checkpoint before shutdown. */
  185. {
  186.     LfsFileLayout          *layoutPtr = &(lfsPtr->fileLayout);
  187.     LfsFileLayoutParams          *paramsPtr = &(lfsPtr->superBlock.fileLayout);
  188.     /*
  189.      * Initialize the filelayout structures for this file system.
  190.      */
  191.     layoutPtr->params = *paramsPtr;
  192.  
  193.     LfsDescCacheInit(lfsPtr);
  194.     Sync_LockInitDynamic(&(lfsPtr->logLock), "LfsLogLock");
  195.     DirLogInit(lfsPtr);
  196.  
  197.     return SUCCESS;
  198. }
  199.  
  200.  
  201. /*
  202.  *----------------------------------------------------------------------
  203.  *
  204.  * LfsFileLayoutDetach --
  205.  *
  206.  *    Detach routine for file layout module. 
  207.  *
  208.  * Results:
  209.  *    SUCCESS if attaching is going ok.
  210.  *
  211.  * Side effects:
  212.  *    Many
  213.  *
  214.  *----------------------------------------------------------------------
  215.  */
  216. /*ARGSUSED*/
  217. ReturnStatus
  218. LfsFileLayoutDetach(lfsPtr)
  219.     Lfs   *lfsPtr;         /* File system for attach. */
  220. {
  221.  
  222.     LfsDescCacheDestory(lfsPtr);
  223.     DirLogDestory(lfsPtr);
  224.  
  225.     return SUCCESS;
  226. }
  227.  
  228.  
  229.  
  230.  
  231. /*
  232.  *----------------------------------------------------------------------
  233.  *
  234.  * LfsFileLayoutProc --
  235.  *
  236.  *    Routine to handle layout of file block in segments.
  237.  *
  238.  * Results:
  239.  *    TRUE if more data needs to be written, FALSE if this module is
  240.  *    happy for the time being.
  241.  *
  242.  * Side effects:
  243.  *    
  244.  *
  245.  *----------------------------------------------------------------------
  246.  */
  247.  
  248. Boolean
  249. LfsFileLayoutProc(segPtr, flags, clientDataPtr)
  250.     LfsSeg *segPtr;        /* Segment to place data blocks in. */
  251.     int    flags;        /* Cleaning flags */
  252.     ClientData    *clientDataPtr;
  253. {
  254.     Lfs            *lfsPtr =   segPtr->lfsPtr;
  255.     LfsFileLayout    *layoutPtr = &(lfsPtr->fileLayout);
  256.     Fscache_FileInfo    *cacheInfoPtr;
  257.     Boolean        full, fsyncOnly;
  258.     FileSegLayout  *segLayoutDataPtr;
  259.     int          token;
  260.  
  261.      /*
  262.       * Next spill the file with dirty blocks into the segment. 
  263.       */
  264.      LFS_STATS_INC(lfsPtr->stats.layout.calls);
  265.      full = FALSE;
  266.  
  267.      fsyncOnly = ((flags & (LFS_CLEANING_LAYOUT|LFS_CHECKPOINT_LAYOUT)) == 0);
  268.      if (flags & LFS_CLEANING_LAYOUT) {
  269.      token = CLEANING_TOKEN;
  270.      } else if (flags & LFS_CHECKPOINT_LAYOUT) {
  271.      token = CHECKPOINT_TOKEN;
  272.      } else {
  273.      token = WRITEBACK_TOKEN;
  274.      }
  275.      if (*clientDataPtr == (ClientData) NIL) {
  276.  
  277.     /*
  278.      * Allocate a FileSegLayout data structure for this segment. 
  279.      */
  280.      segLayoutDataPtr = (FileSegLayout *) malloc(sizeof(FileSegLayout));
  281.      *clientDataPtr = (ClientData) segLayoutDataPtr;
  282.      segLayoutDataPtr->numDescSlotsLeft = 0;
  283.      segLayoutDataPtr->maxElements = LfsSegSizeInBlocks(lfsPtr);
  284.      List_Init(&segLayoutDataPtr->fileList);
  285.      List_Init(&segLayoutDataPtr->blockList);
  286.      segLayoutDataPtr->activeFilePtr = (Fscache_FileInfo *) NIL;
  287.      List_Init(&segLayoutDataPtr->dirLogListHdr);
  288.      } else {
  289.      segLayoutDataPtr = (FileSegLayout *) *clientDataPtr;
  290.      }
  291.      cacheInfoPtr = (Fscache_FileInfo *) NIL;
  292.      /*
  293.       * Choose the first file. If the last call to layout data into this
  294.       * segment ended with a partially layed out file, start with that file.
  295.       */
  296.      if (segLayoutDataPtr->activeFilePtr == (Fscache_FileInfo *) NIL) { 
  297.       /*
  298.        * Last param is for ASPLOS.  Remove when done.  Mary 2/15/92.
  299.        */
  300.       full = AddDirLogBlocks(lfsPtr, segPtr, segLayoutDataPtr, token);
  301.       if (!full) { 
  302.           cacheInfoPtr = Fscache_GetDirtyFile(lfsPtr->domainPtr->backendPtr, 
  303.             fsyncOnly, LfsFileMatch, (ClientData) token);
  304.       }
  305.      } else {
  306.      cacheInfoPtr = segLayoutDataPtr->activeFilePtr;
  307.      }
  308.      while (!full && (cacheInfoPtr != (Fscache_FileInfo *) NIL)) {
  309.        LFS_STATS_INC(lfsPtr->stats.layout.dirtyFiles);
  310.        full = PlaceFileInSegment(lfsPtr, segPtr, cacheInfoPtr, layoutPtr,
  311.             token,  segLayoutDataPtr);
  312.        if (full) {
  313.            LFS_STATS_INC(lfsPtr->stats.layout.filledRegion);
  314.            segLayoutDataPtr->activeFilePtr = cacheInfoPtr;
  315.            break;
  316.        }
  317.        List_Insert((List_Links *) cacheInfoPtr, 
  318.                 LIST_ATREAR(&segLayoutDataPtr->fileList));
  319.       /*
  320.        * Last param is for ASPLOS.  Remove when done.  Mary 2/15/92.
  321.        */
  322.        full = AddDirLogBlocks(lfsPtr, segPtr, segLayoutDataPtr, token);
  323.        if (!full) { 
  324.            cacheInfoPtr = Fscache_GetDirtyFile(
  325.             lfsPtr->domainPtr->backendPtr, 
  326.             FALSE, LfsFileMatch, (ClientData) token);
  327.        }
  328.     }
  329.     if (!full && List_IsEmpty(&segLayoutDataPtr->fileList) &&
  330.        List_IsEmpty(&segLayoutDataPtr->dirLogListHdr)) { 
  331.     free((char *) *clientDataPtr);
  332.     *clientDataPtr = (ClientData) NIL;
  333.     }
  334.     return full;
  335.  
  336. }
  337.  
  338.  
  339.  
  340. /*
  341.  *----------------------------------------------------------------------
  342.  *
  343.  * FileLayoutCheckpoint --
  344.  *
  345.  *    Routine to handle checkpointing of the file layout data.
  346.  *
  347.  * Results:
  348.  *    TRUE if more data needs to be written, FALSE if this module is
  349.  *    checkpointed.
  350.  *
  351.  * Side effects:
  352.  *    Many
  353.  *
  354.  *----------------------------------------------------------------------
  355.  */
  356. /*ARGSUSED*/
  357. Boolean
  358. LfsFileLayoutCheckpoint(segPtr, flags, checkPointPtr,  checkPointSizePtr,
  359.             clientDataPtr)
  360.     LfsSeg *segPtr;        /* Segment containing data for checkpoint. */
  361.     int       flags;        /* Flags. */
  362.     char   *checkPointPtr;      /* Buffer to write checkpoint data. */
  363.     int       *checkPointSizePtr;  /* Bytes added to the checkpoint area.*/
  364.     ClientData *clientDataPtr;
  365. {
  366.     Boolean full;
  367.  
  368.     /*
  369.      * Write-back everything that is dirty.
  370.      */
  371.     full = LfsFileLayoutProc(segPtr, LFS_CHECKPOINT_LAYOUT, clientDataPtr);
  372.     return full;
  373.  
  374. }
  375.  
  376. /*
  377.  *----------------------------------------------------------------------
  378.  *
  379.  * FileLayoutWriteDone --
  380.  *
  381.  *    Routine to handle finishing of file layout writes
  382.  *
  383.  * Results:
  384.  *    None
  385.  *
  386.  * Side effects:
  387.  *    Many
  388.  *
  389.  *----------------------------------------------------------------------
  390.  */
  391. /*ARGSUSED*/
  392. void
  393. LfsFileLayoutWriteDone(segPtr, flags, clientDataPtr)
  394.     LfsSeg *segPtr;        /* Segment containing data for checkpoint. */
  395.     int       flags;        /* Flags for checkpoint */
  396.     ClientData *clientDataPtr;
  397. {
  398.     Lfs          *lfsPtr = segPtr->lfsPtr;
  399.     LfsSegElement *bufferPtr = LfsSegGetBufferPtr(segPtr);
  400.     char     *summaryPtr =  LfsSegGetSummaryPtr(segPtr);
  401.     char     *limitPtr;
  402.     Fscache_Block *blockPtr;
  403.     Fscache_FileInfo *cacheInfoPtr;
  404.     FileSegLayout  *segLayoutDataPtr;
  405.  
  406.     limitPtr = summaryPtr + LfsSegSummaryBytesLeft(segPtr); 
  407.     while (summaryPtr < limitPtr) { 
  408.     switch (*(unsigned short *) summaryPtr) {
  409.     case LFS_FILE_LAYOUT_DESC: {
  410. #ifdef notdef
  411.        LfsFileDescriptor    *descPtr;
  412.        int        i;
  413.        /*
  414.         * A block of descriptors.  For each descriptor we now can 
  415.         * update the descriptor map to point the descriptor at it.
  416.         */
  417.         descPtr = (LfsFileDescriptor *) bufferPtr->address;
  418.         for (i = 0; (i < layoutPtr->params.descPerBlock) && 
  419.              (descPtr->common.flags != 0); i++) {
  420.          UpdateIndex(lfsPtr, descPtr->fileNumber, 
  421.                     LfsSegDiskAddress(segPtr,bufferPtr));
  422.         }
  423. #endif
  424.         LFS_STATS_INC(lfsPtr->stats.layout.descBlockWritten);
  425.         LfsDescCacheBlockRelease(segPtr->lfsPtr, bufferPtr->clientData, 
  426.                 FALSE);
  427.         bufferPtr++;
  428.         summaryPtr += sizeof(LfsFileLayoutDesc);
  429.         break;
  430.     }
  431.     case LFS_FILE_LAYOUT_DATA:  {
  432.         LfsFileLayoutSummary *fileSumPtr;
  433.         /* 
  434.          * All these records should be pointing to a cache blocks which
  435.          * must be released.
  436.          */
  437.         fileSumPtr = (LfsFileLayoutSummary *) summaryPtr;
  438.         bufferPtr += fileSumPtr->numDataBlocks;
  439.         summaryPtr += (sizeof(LfsFileLayoutSummary) + 
  440.                fileSumPtr->numDataBlocks * sizeof(int));
  441.         break;
  442.     }
  443.     case LFS_FILE_LAYOUT_DIR_LOG: {
  444.         LfsFileLayoutLog    *logSumPtr = (LfsFileLayoutLog *) summaryPtr;
  445.          /*
  446.           * Because we copied and truncated the log during layout we 
  447.           * don't need to do anything on write complete.
  448.           */
  449.         summaryPtr = summaryPtr + sizeof(LfsFileLayoutLog);
  450.         bufferPtr += logSumPtr->numDataBlocks;
  451.         break;
  452.     }
  453.     case LFS_FILE_LAYOUT_DBL_INDIRECT: 
  454.     case LFS_FILE_LAYOUT_INDIRECT: 
  455.     default:
  456.         panic("Bad file block type in summary block");
  457.     }
  458.     }
  459.     LfsSegSetBufferPtr(segPtr, bufferPtr);
  460.     if (*clientDataPtr != (ClientData) NIL) {
  461.     LFS_STATS_INC(lfsPtr->stats.layout.segWrites);
  462.     segLayoutDataPtr = (FileSegLayout *) *clientDataPtr;
  463.     FreeDirLogBlocks(lfsPtr, segPtr, segLayoutDataPtr);
  464.     while (!List_IsEmpty(&segLayoutDataPtr->blockList)) {
  465.         blockPtr = (Fscache_Block *)
  466.                 List_First(&segLayoutDataPtr->blockList);
  467.         List_Remove((List_Links *)blockPtr);
  468.         LFS_STATS_INC(lfsPtr->stats.layout.cacheBlocksWritten);
  469.         Fscache_ReturnDirtyBlock(blockPtr, SUCCESS);
  470.     }
  471.     while (!List_IsEmpty(&segLayoutDataPtr->fileList)) {
  472.         cacheInfoPtr = 
  473.         (Fscache_FileInfo *) List_First(&segLayoutDataPtr->fileList);
  474.         List_Remove((List_Links *)cacheInfoPtr);
  475.         LFS_STATS_INC(lfsPtr->stats.layout.filesWritten);
  476.         Fscache_ReturnDirtyFile(cacheInfoPtr, TRUE);
  477.     }
  478.     if (segLayoutDataPtr->activeFilePtr != (Fscache_FileInfo *) NIL) {
  479.         Fscache_ReturnDirtyFile(segLayoutDataPtr->activeFilePtr, TRUE);
  480.     }
  481.     free((char *) *clientDataPtr);
  482.     *clientDataPtr = (ClientData) NIL;
  483.     }
  484.     return;
  485.  
  486. }
  487.  
  488.  
  489. /*
  490.  *----------------------------------------------------------------------
  491.  *
  492.  * FileLayoutClean --
  493.  *
  494.  *    Routine to handle cleaning of file data blocks.
  495.  *
  496.  * Results:
  497.  *    TRUE if we couldn't clean the segment.
  498.  *
  499.  * Side effects:
  500.  *    
  501.  *
  502.  *----------------------------------------------------------------------
  503.  */
  504.  
  505. Boolean
  506. LfsFileLayoutClean(segPtr, sizePtr, numCacheBlocksPtr, clientDataPtr)
  507.     LfsSeg *segPtr;    /* Segment containing data to clean. */
  508.     int       *sizePtr;
  509.     int    *numCacheBlocksPtr;
  510.     ClientData *clientDataPtr;
  511. {
  512.     Lfs           *lfsPtr = segPtr->lfsPtr;
  513.     LfsFileLayout  *layoutPtr = &(lfsPtr->fileLayout);
  514.     LfsFileLayoutSummary  *fileSumPtr;
  515.     char    *summaryPtr, *limitPtr;
  516.     int  blockOffset, fsBlocks;
  517.     LfsDiskAddr address;
  518.     ReturnStatus    status;
  519.     Boolean    error;
  520.  
  521.      error = FALSE;
  522.      fsBlocks = LfsBytesToBlocks(lfsPtr, FS_BLOCK_SIZE);
  523.      summaryPtr =  LfsSegGetSummaryPtr(segPtr);
  524.      limitPtr = summaryPtr + LfsSegSummaryBytesLeft(segPtr);
  525.      address = LfsSegDiskAddress(segPtr, LfsSegGetBufferPtr(segPtr));
  526.      blockOffset = 0;
  527.      LFS_STATS_INC(lfsPtr->stats.layout.cleanings);
  528.      while ((summaryPtr < limitPtr) && !error) { 
  529.     switch (*(unsigned short *) summaryPtr) {
  530.     case LFS_FILE_LAYOUT_DESC: {
  531.         LfsDiskAddr diskAddr;
  532.         int        fileNumber;
  533.         int        slot, size;
  534.         LfsFileDescriptor    *descPtr;
  535.         char        *blockStartPtr;
  536.         ClientData descCachePtr = (ClientData) NIL;
  537.         /*
  538.          * A block of descriptors.  For each descriptor that is live
  539.          * (being pointed to by the descriptor map) we bring it into
  540.          * the system and mark it as dirty. 
  541.          */
  542.         LFS_STATS_INC(lfsPtr->stats.layout.descBlocksCleaned);
  543.         size = layoutPtr->params.descPerBlock * sizeof(LfsFileDescriptor);
  544.         blockOffset += LfsBytesToBlocks(lfsPtr, size);
  545.         blockStartPtr = LfsSegFetchBytes(segPtr, 
  546.                 segPtr->curBlockOffset + blockOffset, size);
  547.         descPtr = (LfsFileDescriptor *)blockStartPtr;
  548.         for (slot = 0; slot < layoutPtr->params.descPerBlock; slot++) {
  549.         Fs_FileID fileID;
  550.         Fsio_FileIOHandle *newHandlePtr;
  551.         LfsDiskAddr newDiskAddr;
  552.         /*
  553.          * The descriptor block is terminated by an inode
  554.          * with a zero magic number.
  555.          */
  556.         if (descPtr[slot].common.magic == 0) {
  557.             break;
  558.         }
  559.         if (descPtr[slot].common.magic != FSDM_FD_MAGIC) {
  560.             LfsError(lfsPtr, FAILURE, "Bad descriptor magic number.\n");
  561.             continue;
  562.         }
  563.         if (!(descPtr[slot].common.flags & FSDM_FD_ALLOC)) {
  564.             /*
  565.              * Skip over any FREE inodes.
  566.              */
  567.             continue;
  568.         }
  569.         fileNumber = descPtr[slot].fileNumber;
  570.         status = LfsDescMapGetDiskAddr(lfsPtr, fileNumber, &diskAddr);
  571.         /*
  572.          * If the file is not allocated or this descriptor is not
  573.          * the most current copy, skip it.
  574.          */
  575.         LfsDiskAddrPlusOffset(address,-blockOffset, &newDiskAddr);
  576.         if ((status == FS_FILE_NOT_FOUND) || 
  577.             ((status == SUCCESS) && 
  578.               !LfsSameDiskAddr(diskAddr, newDiskAddr))) {
  579.             continue;
  580.         }
  581.         if (status != SUCCESS) {
  582.             LfsError(lfsPtr, status, 
  583.             "Bad file number in descriptor block.\n");
  584.             continue;
  585.         }
  586.             LFS_STATS_INC(lfsPtr->stats.layout.descCopied);
  587.         if (descCachePtr == (ClientData) NIL) {
  588.             char *blockAddrPtr;
  589.             /*
  590.              * We get to read it into the cache if its not already
  591.              * there. 
  592.              */
  593.             blockAddrPtr = blockStartPtr;
  594.             descCachePtr = LfsDescCacheBlockInit(lfsPtr, diskAddr, 
  595.                             TRUE, 
  596.                             &blockAddrPtr);
  597.             if (descCachePtr == (ClientData) NIL) {
  598.             printf("Can't fetch descriptor block\n");
  599.             error = TRUE;
  600.             break;
  601.             }
  602.         }
  603.         /*
  604.          * Grab a handle for this file.
  605.          */
  606.         fileID.type = FSIO_LCL_FILE_STREAM;
  607.         fileID.serverID = rpc_SpriteID;
  608.         fileID.major = lfsPtr->domainPtr->domainNumber;
  609.         fileID.minor = fileNumber;
  610.         status = Fsio_LocalFileHandleInit(&fileID, (char *) NIL, 
  611.                     (Fsdm_FileDescriptor *) NIL, TRUE, 
  612.                     &newHandlePtr);
  613.         if (status == FS_WOULD_BLOCK) {
  614.             error = TRUE;
  615.             break;
  616.         }
  617.         if (status == FS_FILE_REMOVED) {
  618.             continue;
  619.         }
  620.         if (status != SUCCESS) {
  621.             LfsError(lfsPtr, status, 
  622.                 "Can't get handle to clean file\n");
  623.         }
  624.         *sizePtr += sizeof(LfsFileDescriptor);
  625.         Fscache_PutFileOnDirtyList(&newHandlePtr->cacheInfo, 
  626.                     (int)(FSCACHE_FILE_BEING_CLEANED |
  627.                     FSCACHE_FILE_DESC_DIRTY));
  628.         Fsutil_HandleRelease(newHandlePtr, TRUE);
  629.         }
  630.         if (descCachePtr != (ClientData) NIL) {
  631.         LfsDescCacheBlockRelease(lfsPtr, descCachePtr, TRUE);
  632.         }
  633.         /*
  634.          * Skip over the summary bytes describing this block. 
  635.          */
  636.         summaryPtr += sizeof(LfsFileLayoutDesc);
  637.         break;
  638.     }
  639.     case LFS_FILE_LAYOUT_DATA: {
  640.         LfsDiskAddr diskAddress;
  641.         int        *blockArray;
  642.         int             startBlockOffset, i;
  643.         unsigned short    curTruncVersion;
  644.         /*
  645.          * We ran into a data block. If it is still alive bring it into
  646.          * the cache. 
  647.          */
  648.          fileSumPtr = (LfsFileLayoutSummary *) summaryPtr;
  649.          startBlockOffset = blockOffset;
  650.          /*
  651.           * Liveness check.   First see if the version number is
  652.           * the same and the file is still allocated.
  653.           */
  654.           LFS_STATS_INC(lfsPtr->stats.layout.fileCleaned);
  655.          status = LfsDescMapGetVersion(lfsPtr, 
  656.             (int)fileSumPtr->fileNumber, &curTruncVersion);
  657.          if ((status == SUCCESS) && 
  658.          (curTruncVersion == fileSumPtr->truncVersion)) {
  659.         Fs_FileID fileID;
  660.         int      numBlocks;
  661.         Fsio_FileIOHandle *newHandlePtr;
  662.  
  663.             LFS_STATS_INC(lfsPtr->stats.layout.fileVersionOk);
  664.         /*
  665.          * So far so good.  File is allocated and version number 
  666.          * says it hasn't been deleted or truncated. Grap a 
  667.          * handle for the file a check to see if the blocks 
  668.          * are still a member of the file.
  669.          */
  670.         fileID.type = FSIO_LCL_FILE_STREAM;
  671.         fileID.serverID = rpc_SpriteID;
  672.         fileID.major = lfsPtr->domainPtr->domainNumber;
  673.         fileID.minor = fileSumPtr->fileNumber;
  674.         status = Fsio_LocalFileHandleInit(&fileID, (char *) NIL, 
  675.                     (Fsdm_FileDescriptor *) NIL, TRUE, 
  676.                     &newHandlePtr);
  677.         if (status == FS_WOULD_BLOCK) {
  678.             LFS_STATS_INC(lfsPtr->stats.layout.cleanLockedHandle);
  679.             error = TRUE;
  680.             break;
  681.         }
  682.         if (status != SUCCESS) {
  683.             if (status == FS_FILE_NOT_FOUND) {
  684.             /*
  685.              * Someone just deleted the file out from under us.
  686.              */
  687.             LFS_STATS_INC(lfsPtr->stats.layout.cleanNoHandle);
  688.             goto noHandle;
  689.             }
  690.             LfsError(lfsPtr, status,
  691.                 "Can't get handle to clean file\n");
  692.         }
  693.         /*
  694.          * For each block ... 
  695.          */
  696.         blockArray = (int *)
  697.             (summaryPtr + sizeof(LfsFileLayoutSummary));
  698.         /*
  699.          * Careful with the first block because it could be a 
  700.          * fragment.
  701.          */
  702.         numBlocks = fileSumPtr->numBlocks - 
  703.                 (fileSumPtr->numDataBlocks-1) * fsBlocks;
  704.             LFS_STATS_ADD(lfsPtr->stats.layout.blocksCleaned,
  705.                     fileSumPtr->numBlocks);
  706.         for (i = 0; i < fileSumPtr->numDataBlocks; i++) {
  707.             LfsDiskAddr newDiskAddr;
  708.             blockOffset += numBlocks;
  709.             status = LfsFile_GetIndex(newHandlePtr, blockArray[i],
  710.                 FSCACHE_CANT_BLOCK|FSCACHE_DONT_BLOCK,
  711.                 &diskAddress);
  712.             LfsDiskAddrPlusOffset(address, -blockOffset, &newDiskAddr);
  713.             if ((status == SUCCESS) && 
  714.               LfsSameDiskAddr(diskAddress, newDiskAddr)) { 
  715.             int    blockSize, flags;
  716.             Boolean     found;
  717.             Fscache_Block *blockPtr;
  718.             /*
  719.              * The block exists and is at the location we are
  720.              * cleaning, bring it into the cache. Be a little
  721.              * careful about short blocks.
  722.              */
  723.                 LFS_STATS_ADD(lfsPtr->stats.layout.blocksCopied,numBlocks);
  724.                 blockSize = LfsBlocksToBytes(lfsPtr, numBlocks);
  725.             flags = (FSCACHE_IO_IN_PROGRESS | FSCACHE_CANT_BLOCK | 
  726.                         FSCACHE_DONT_BLOCK |
  727.                       ((blockArray[i] >= 0) ? FSCACHE_DATA_BLOCK :
  728.                               FSCACHE_IND_BLOCK));
  729.  
  730.                 Fscache_FetchBlock(&newHandlePtr->cacheInfo,
  731.                       blockArray[i], flags, &blockPtr, &found);
  732.             if (blockPtr == (Fscache_Block *) NIL) {
  733.                 printf("Can't fetch cache block <%d,%d> for cleaning.\n", fileSumPtr->fileNumber, blockArray[i]);
  734.                 error = TRUE;
  735.                 break;
  736.             }
  737.             if (!found) {
  738.                 char *dPtr;
  739.                 /*
  740.                  * Its not in the cache already, copy it in.
  741.                  * Handle the cache that it in a short fragment.
  742.                  */
  743.                 if (blockArray[i] >= 0) {
  744.                 if (blockArray[i] * FS_BLOCK_SIZE + 
  745.                         blockSize - 1 >
  746.                     newHandlePtr->descPtr->lastByte) {
  747.                     blockSize = newHandlePtr->descPtr->lastByte
  748.                     - blockArray[i] * FS_BLOCK_SIZE + 1;
  749.                 }
  750.                 } else if (blockSize != FS_BLOCK_SIZE) {
  751.                 panic("Illegal sized indirect block.\n");
  752.                 }
  753.                 if (blockSize <= 0) { 
  754.                 panic("Illegal sized block.\n");
  755.                 }
  756.  
  757.                 dPtr = LfsSegFetchBytes(segPtr, segPtr->curBlockOffset + blockOffset, 
  758.                     blockSize);
  759.                 bcopy(dPtr, blockPtr->blockAddr, blockSize);
  760.                 bzero(blockPtr->blockAddr + blockSize,
  761.                     FS_BLOCK_SIZE - blockSize);
  762.                 Fscache_UnlockBlock(blockPtr,
  763.                         (time_t)Fsutil_TimeInSeconds(),
  764.                         -1, blockSize, 
  765.                         FSCACHE_BLOCK_BEING_CLEANED);
  766.  
  767.             } else { 
  768.                 /*
  769.                  * Checking it out.
  770.                  */
  771. #ifdef ERROR_CHECK
  772.                 char *dPtr;
  773.                 Boolean bad;
  774.                 dPtr = LfsSegFetchBytes(segPtr, blockOffset + segPtr->curBlockOffset, 
  775.                     blockSize);
  776.                 bad = bcmp(dPtr, blockPtr->blockAddr, 
  777.                     blockPtr->blockSize);
  778.                 if (bad && !(blockPtr->flags & FSCACHE_BLOCK_DIRTY)) {
  779.                 panic("Block cleaned doesn't match block.\n");
  780.                 }
  781. #endif
  782.                 Fscache_UnlockBlock(blockPtr,
  783.                         (time_t)Fsutil_TimeInSeconds(),
  784.                         -1, blockPtr->blockSize, 
  785.                         FSCACHE_BLOCK_BEING_CLEANED);
  786.                LFS_STATS_ADD(lfsPtr->stats.layout.blocksCopiedHit,
  787.                     numBlocks);
  788.             }
  789.             (*sizePtr) += blockSize;
  790.             (*numCacheBlocksPtr)++;
  791.             } else if (status != SUCCESS) {
  792.             printf("Can't fetch index for cleaning <%d,%d>\n",
  793.                     fileSumPtr->fileNumber, blockArray[i]);
  794.             error = TRUE;
  795.             break;
  796.             }
  797.             /*
  798.              * All the blocks after the first one must be FS_BLOCK_SIZE.
  799.              */
  800.             numBlocks = fsBlocks;
  801.         }
  802.         Fsutil_HandleRelease(newHandlePtr, TRUE);
  803.         } else {
  804. #ifdef TRACING
  805.             {
  806.                 LfsTraceRecord rec;
  807.                 rec.fileNumber = fileSumPtr->fileNumber;
  808.                 rec.diskAddr = address;
  809.                 rec.status = status;
  810.                 rec.curTruncVersion = curTruncVersion;
  811.                 Trace_Insert(lfsTraceHdrPtr, 0, (ClientData)&rec);
  812.             }
  813. #endif /* TRACING */
  814.         }
  815.      noHandle:
  816.         blockOffset = startBlockOffset + fileSumPtr->numBlocks;
  817.         summaryPtr += sizeof(LfsFileLayoutSummary) + 
  818.                 fileSumPtr->numDataBlocks * sizeof(int); 
  819.         break;
  820.       }
  821.  
  822.     case LFS_FILE_LAYOUT_DIR_LOG: {
  823.         LfsFileLayoutLog    *logSumPtr;
  824.         /* 
  825.          * Directory log info is not needed during clean so we 
  826.          * just skip over it.
  827.          */
  828.          logSumPtr = (LfsFileLayoutLog *) summaryPtr;
  829.          summaryPtr += sizeof(LfsFileLayoutLog);
  830.          blockOffset += logSumPtr->numBlocks;
  831.          break;
  832.     }
  833.     case LFS_FILE_LAYOUT_DBL_INDIRECT: 
  834.     case LFS_FILE_LAYOUT_INDIRECT: 
  835.     default: {
  836.         panic("Unknown type");
  837.     }
  838.       }
  839.     }
  840.  
  841.     return error;
  842.  
  843. }
  844. #ifdef VERIFY_CLEAN
  845.  
  846. /*
  847.  *----------------------------------------------------------------------
  848.  *
  849.  * FileLayoutVerifyClean --
  850.  *
  851.  *    After a segment is cleaned this routine is used to verify that
  852.  *    it really is clean. 
  853.  *
  854.  * Results:
  855.  *    TRUE if the segment is clean, FALSE otherwise.
  856.  *
  857.  * Side effects:
  858.  *    panicks if the segmetn isn't clean
  859.  *    
  860.  *
  861.  *----------------------------------------------------------------------
  862.  */
  863.  
  864. Boolean
  865. LfsFileLayoutCleanVerify(segPtr)
  866.     LfsSeg *segPtr;    /* Segment to verify clean. */
  867. {
  868.     Lfs           *lfsPtr = segPtr->lfsPtr;
  869.     LfsFileLayout  *layoutPtr = &(lfsPtr->fileLayout);
  870.     LfsFileLayoutSummary  *fileSumPtr;
  871.     char    *summaryPtr, *limitPtr;
  872.     int  blockOffset, fsBlocks;
  873.     LfsDiskAddr address;
  874.     ReturnStatus    status;
  875.     Boolean    error;
  876.  
  877.      error = FALSE;
  878.      fsBlocks = LfsBytesToBlocks(lfsPtr, FS_BLOCK_SIZE);
  879.      summaryPtr =  LfsSegGetSummaryPtr(segPtr);
  880.      limitPtr = summaryPtr + LfsSegSummaryBytesLeft(segPtr);
  881.      address = LfsSegDiskAddress(segPtr, LfsSegGetBufferPtr(segPtr));
  882.      blockOffset = 0;
  883.      while ((summaryPtr < limitPtr) && !error) { 
  884.     switch (*(unsigned short *) summaryPtr) {
  885.     case LFS_FILE_LAYOUT_DESC: {
  886.         LfsDiskAddr diskAddr;
  887.         int        fileNumber;
  888.         int        slot, size;
  889.         LfsFileDescriptor    *descPtr;
  890.         char        *blockStartPtr;
  891.         ClientData descCachePtr = (ClientData) NIL;
  892.         /*
  893.          * A block of descriptors.  For each descriptor that is live
  894.          * (being pointed to by the descriptor map) we bring it into
  895.          * the system and mark it as dirty. 
  896.          */
  897.         size = layoutPtr->params.descPerBlock * sizeof(LfsFileDescriptor);
  898.         blockOffset += LfsBytesToBlocks(lfsPtr, size);
  899.         blockStartPtr = LfsSegFetchBytes(segPtr, 
  900.                 segPtr->curBlockOffset + blockOffset, size);
  901.         descPtr = (LfsFileDescriptor *)blockStartPtr;
  902.         for (slot = 0; slot < layoutPtr->params.descPerBlock; slot++) {
  903.         LfsDiskAddr newDiskAddr;
  904.         /*
  905.          * The descriptor block is terminated by an inode
  906.          * with a zero magic number.
  907.          */
  908.         if (descPtr[slot].common.magic == 0) {
  909.             break;
  910.         }
  911.         if (descPtr[slot].common.magic != FSDM_FD_MAGIC) {
  912.             LfsError(lfsPtr, FAILURE, "Bad descriptor magic number.\n");
  913.             continue;
  914.         }
  915.         if (!(descPtr[slot].common.flags & FSDM_FD_ALLOC)) {
  916.             /*
  917.              * Skip over any FREE inodes.
  918.              */
  919.             continue;
  920.         }
  921.         fileNumber = descPtr[slot].fileNumber;
  922.         status = LfsDescMapGetDiskAddr(lfsPtr, fileNumber, &diskAddr);
  923.         /*
  924.          * If the file is not allocated or this descriptor is not
  925.          * the most current copy, skip it.
  926.          */
  927.         LfsDiskAddrPlusOffset(address,-blockOffset, &newDiskAddr);
  928.         if ((status == FS_FILE_NOT_FOUND) || 
  929.             ((status == SUCCESS) && 
  930.               !LfsSameDiskAddr(diskAddr, newDiskAddr))) {
  931.             continue;
  932.         }
  933.         if (status != SUCCESS) {
  934.             LfsError(lfsPtr, status, 
  935.             "Bad file number in descriptor block.\n");
  936.             continue;
  937.         }
  938.         for (;;) {
  939.             panic("\"Clean\" segment contains active descriptor\n");
  940.         }
  941.         }
  942.         if (descCachePtr != (ClientData) NIL) {
  943.         LfsDescCacheBlockRelease(lfsPtr, descCachePtr, TRUE);
  944.         }
  945.         /*
  946.          * Skip over the summary bytes describing this block. 
  947.          */
  948.         summaryPtr += sizeof(LfsFileLayoutDesc);
  949.         break;
  950.     }
  951.     case LFS_FILE_LAYOUT_DATA: {
  952.         LfsDiskAddr diskAddress;
  953.         int        *blockArray;
  954.         int             startBlockOffset, i;
  955.         unsigned short    curTruncVersion;
  956.         /*
  957.          * We ran into a data block. If it is still alive bring it into
  958.          * the cache. 
  959.          */
  960.          fileSumPtr = (LfsFileLayoutSummary *) summaryPtr;
  961.          startBlockOffset = blockOffset;
  962.          /*
  963.           * Liveness check.   First see if the version number is
  964.           * the same and the file is still allocated.
  965.           */
  966.          status = LfsDescMapGetVersion(lfsPtr, 
  967.             (int)fileSumPtr->fileNumber, &curTruncVersion);
  968.          if ((status == SUCCESS) && 
  969.          (curTruncVersion == fileSumPtr->truncVersion)) {
  970.         Fs_FileID fileID;
  971.         int      numBlocks;
  972.         Fsio_FileIOHandle *newHandlePtr;
  973.  
  974.         /*
  975.          * So far so good.  File is allocated and version number 
  976.          * says it hasn't been deleted or truncated. Grap a 
  977.          * handle for the file a check to see if the blocks 
  978.          * are still a member of the file.
  979.          */
  980.         fileID.type = FSIO_LCL_FILE_STREAM;
  981.         fileID.serverID = rpc_SpriteID;
  982.         fileID.major = lfsPtr->domainPtr->domainNumber;
  983.         fileID.minor = fileSumPtr->fileNumber;
  984.         status = Fsio_LocalFileHandleInit(&fileID, (char *) NIL, 
  985.                     (Fsdm_FileDescriptor *) NIL, TRUE, 
  986.                     &newHandlePtr);
  987.         if (status == FS_WOULD_BLOCK) {
  988.             error = TRUE;
  989.             break;
  990.         }
  991.         if (status != SUCCESS) {
  992.             if (status == FS_FILE_NOT_FOUND) {
  993.             /*
  994.              * Someone just deleted the file out from under us.
  995.              */
  996.             goto noHandle;
  997.             }
  998.             LfsError(lfsPtr, status,
  999.                 "Can't get handle to clean file\n");
  1000.         }
  1001.         /*
  1002.          * For each block ... 
  1003.          */
  1004.         blockArray = (int *)
  1005.             (summaryPtr + sizeof(LfsFileLayoutSummary));
  1006.         /*
  1007.          * Careful with the first block because it could be a 
  1008.          * fragment.
  1009.          */
  1010.         numBlocks = fileSumPtr->numBlocks - 
  1011.                 (fileSumPtr->numDataBlocks-1) * fsBlocks;
  1012.         for (i = 0; i < fileSumPtr->numDataBlocks; i++) {
  1013.             LfsDiskAddr newDiskAddr;
  1014.             blockOffset += numBlocks;
  1015.             status = LfsFile_GetIndex(newHandlePtr, blockArray[i],
  1016.                 FSCACHE_CANT_BLOCK|FSCACHE_DONT_BLOCK,
  1017.                 &diskAddress);
  1018.             LfsDiskAddrPlusOffset(address, -blockOffset, &newDiskAddr);
  1019.             if ((status == SUCCESS) && 
  1020.               LfsSameDiskAddr(diskAddress, newDiskAddr)) { 
  1021.             panic("\"Clean\" segment contains live block\n");
  1022.             } else if (status != SUCCESS) {
  1023.             printf("Can't fetch index for cleaning <%d,%d>\n",
  1024.                     fileSumPtr->fileNumber, blockArray[i]);
  1025.             error = TRUE;
  1026.             break;
  1027.             }
  1028.             /*
  1029.              * All the blocks after the first one must be FS_BLOCK_SIZE.
  1030.              */
  1031.             numBlocks = fsBlocks;
  1032.         }
  1033.         Fsutil_HandleRelease(newHandlePtr, TRUE);
  1034.         } else {
  1035.         }
  1036.      noHandle:
  1037.         blockOffset = startBlockOffset + fileSumPtr->numBlocks;
  1038.         summaryPtr += sizeof(LfsFileLayoutSummary) + 
  1039.                 fileSumPtr->numDataBlocks * sizeof(int); 
  1040.         break;
  1041.       }
  1042.  
  1043.     case LFS_FILE_LAYOUT_DIR_LOG: {
  1044.         LfsFileLayoutLog    *logSumPtr;
  1045.         /* 
  1046.          * Directory log info is not needed during clean so we 
  1047.          * just skip over it.
  1048.          */
  1049.          logSumPtr = (LfsFileLayoutLog *) summaryPtr;
  1050.          summaryPtr += sizeof(LfsFileLayoutLog);
  1051.          blockOffset += logSumPtr->numBlocks;
  1052.          break;
  1053.     }
  1054.     case LFS_FILE_LAYOUT_DBL_INDIRECT: 
  1055.     case LFS_FILE_LAYOUT_INDIRECT: 
  1056.     default: {
  1057.         panic("Unknown type");
  1058.     }
  1059.       }
  1060.     }
  1061.  
  1062.     return error;
  1063.  
  1064. }
  1065. #endif /* VERIFY_CLEAN */
  1066.  
  1067. /*
  1068.  *----------------------------------------------------------------------
  1069.  *
  1070.  * PlaceFileInSegment --
  1071.  *
  1072.  *    Place specified file dirty in segment.
  1073.  *
  1074.  * Results:
  1075.  *    TRUE if the segment filled before the file was fully added.
  1076.  *
  1077.  * Side effects:
  1078.  *    None.
  1079.  *
  1080.  *----------------------------------------------------------------------
  1081.  */
  1082. static Boolean 
  1083. PlaceFileInSegment(lfsPtr, segPtr, cacheInfoPtr, layoutPtr, token,
  1084.         segLayoutDataPtr)
  1085.     Lfs        *lfsPtr;    /* File system. */
  1086.     LfsSeg    *segPtr;    /* Segment to place data. */
  1087.     Fscache_FileInfo *cacheInfoPtr;    /* File to place in segment. */
  1088.     LfsFileLayout     *layoutPtr;   /* File layout info. */
  1089.     int             token;        /* Block selector token. */
  1090.     FileSegLayout  *segLayoutDataPtr; /* Current layout data for segment. */
  1091. {
  1092.     LfsFileLayoutSummary *fileSumPtr;
  1093.     Boolean    full;
  1094.     LfsSegElement    *bufferPtr;
  1095.     char    *summaryPtr;
  1096.     int        lfsBlocksPerBlock, lastDirtyBlock;
  1097.     int        blockType;
  1098.     int        blocksNeeded, bytesNeeded, blocksLeft;
  1099.     ReturnStatus    status;
  1100.     Fscache_Block    *blockPtr, *firstBlockPtr;
  1101.     Fsdm_FileDescriptor *descPtr;
  1102.  
  1103.     if (cacheInfoPtr == (Fscache_FileInfo *) NIL) {
  1104.     return FALSE;
  1105.     }
  1106.     descPtr = ((Fsio_FileIOHandle *)(cacheInfoPtr->hdrPtr))->descPtr;
  1107.     /*
  1108.      * Layout the blocks of the file into the segment starting with the
  1109.      * data blocks.
  1110.      */
  1111.     full = FALSE;
  1112.     fileSumPtr = (LfsFileLayoutSummary *) NIL;
  1113.     lfsBlocksPerBlock = LfsBytesToBlocks(lfsPtr, FS_BLOCK_SIZE);
  1114.     for (blockType = LFS_FILE_LAYOUT_DATA; 
  1115.     (blockType <= LFS_FILE_LAYOUT_DBL_INDIRECT) && !full;  blockType++) { 
  1116.     /*
  1117.      * Do all of one blockType first before going to the next.
  1118.      * Try to checkout just enought blocks that will fit in this
  1119.      * segment. We prefetch the first block so that we know if
  1120.      * we have zero blocks to layout and don't have to add a
  1121.      * LfsFileLayoutSummary.
  1122.      */
  1123.     firstBlockPtr = Fscache_GetDirtyBlock(cacheInfoPtr, BlockMatch,
  1124.                 (ClientData) ((token << 16) | blockType),
  1125.                  &lastDirtyBlock);
  1126.     /*
  1127.      * No more blocks of this type available for this file, go on to 
  1128.      * the next blockType. 
  1129.      */ 
  1130.     if (firstBlockPtr == (Fscache_Block *) NIL) {
  1131.         continue;
  1132.     }
  1133.     if ((firstBlockPtr->blockSize < FS_BLOCK_SIZE) && 
  1134.         (firstBlockPtr->blockNum != descPtr->lastByte/FS_BLOCK_SIZE)) {
  1135.         /*
  1136.          * Only the last block in the file is allowed to be less than 
  1137.          * FS_BLOCK_SIZE. Sometimes the Fscache_Block->blockSize
  1138.          * is incorrect so we patch it for them.
  1139.          */
  1140.         firstBlockPtr->blockSize = FS_BLOCK_SIZE;
  1141.     }
  1142.  
  1143.        /*
  1144.         * Allocate the layout summary bytes of this file if 
  1145.         * we haven't done so already.
  1146.         */
  1147.        if (fileSumPtr == (LfsFileLayoutSummary *) NIL) {
  1148.        /*
  1149.         * Since we haven't done so already, allocate a LfsFileLayoutSummary
  1150.         * for this file in summary block.  Besure there is at least 
  1151.         * enough space for one block. If the block that we justed got 
  1152.         * (ie firstBlockPtr) is the last block in the cache we ensure
  1153.         * that there is enough room for it.  Otherwise we require at 
  1154.         * least a entire blocks worth.
  1155.         */
  1156.        blocksNeeded =  (lastDirtyBlock != 0) ? lfsBlocksPerBlock : 
  1157.                 LfsBytesToBlocks(lfsPtr, 
  1158.                         firstBlockPtr->blockSize);
  1159.        bytesNeeded = sizeof(LfsFileLayoutSummary) + sizeof(int);
  1160.        summaryPtr = LfsSegGrowSummary(segPtr, blocksNeeded, bytesNeeded);
  1161.        if (summaryPtr == (char *) NIL) { 
  1162.            /*
  1163.             * No room in summary. Return block and exit loop.
  1164.         */
  1165.         if (token == CLEANING_TOKEN) {
  1166.             /* 
  1167.              * Reset the flag marking this block as being cleaned
  1168.              * before returning it to the cache.
  1169.              */
  1170.             firstBlockPtr->flags |= FSCACHE_BLOCK_BEING_CLEANED;
  1171.         }
  1172.            Fscache_ReturnDirtyBlock(firstBlockPtr, GEN_EINTR);
  1173.            full = TRUE;
  1174.            break;
  1175.        }
  1176.        /*
  1177.         * Fill in the LfsFileLayoutSummary with the value we 
  1178.         * know now.
  1179.         */
  1180.        fileSumPtr = (LfsFileLayoutSummary *) summaryPtr;
  1181.        fileSumPtr->blockType = LFS_FILE_LAYOUT_DATA;
  1182.        fileSumPtr->numDataBlocks = 0;
  1183.        fileSumPtr->numBlocks = 0; /* Filled in later. */
  1184.        fileSumPtr->fileNumber = cacheInfoPtr->hdrPtr->fileID.minor;
  1185.        status = LfsDescMapGetVersion(lfsPtr, 
  1186.                fileSumPtr->fileNumber, &fileSumPtr->truncVersion);
  1187.        if (status != SUCCESS) {
  1188.            LfsError(lfsPtr, status, "Can't get truncate version number\n");
  1189.        }
  1190.        summaryPtr += sizeof(LfsFileLayoutSummary);
  1191.        LfsSegSetSummaryPtr(segPtr, summaryPtr);
  1192.        }
  1193.        /*
  1194.         * Place the blocks in the segment in reverse order so that
  1195.         * they will occur on disk in forward order. This is done
  1196.     * by looping until we have collected enough blocks to fill the
  1197.     * segments or we run out of cache blocks.  Note that we are
  1198.     * permitted to overrun the segment because the code below will
  1199.     * return the blocks to the cache.
  1200.     *
  1201.     * The first block we push on the list is the block we prefetched
  1202.     * above.
  1203.     */
  1204.        blocksLeft = LfsSegBlocksLeft(segPtr);
  1205.        blockPtr = firstBlockPtr;
  1206.        do {  
  1207.        LFS_STATS_INC(lfsPtr->stats.layout.dirtyBlocks);
  1208.         if ((blockPtr->blockSize < FS_BLOCK_SIZE) && 
  1209.         (blockPtr->blockNum != descPtr->lastByte/FS_BLOCK_SIZE)) {
  1210.         /*
  1211.          * Only the last block in the file is allowed to be less than 
  1212.          * FS_BLOCK_SIZE. Sometimes the Fscache_Block->blockSize
  1213.          * is incorrect so we patch it for them.
  1214.          */
  1215.         blockPtr->blockSize = FS_BLOCK_SIZE;
  1216.         }
  1217.        List_Insert((List_Links *) blockPtr, 
  1218.             LIST_ATFRONT(&segLayoutDataPtr->blockList));
  1219.        blocksLeft -= LfsBytesToBlocks(lfsPtr, blockPtr->blockSize);
  1220.        if (blocksLeft > 0) {
  1221.            blockPtr = Fscache_GetDirtyBlock(cacheInfoPtr, 
  1222.             BlockMatch, (ClientData) ((token << 16) | blockType), 
  1223.             &lastDirtyBlock);
  1224.         }
  1225.     } while ((blocksLeft > 0) && (blockPtr != (Fscache_Block *) NIL));
  1226.  
  1227.     /*
  1228.      * Interate forward thru the blocks we pushed on the list to 
  1229.      * lay them out in the reverse order.  We allow the first
  1230.      * block to layout to be a fragment, so we start off by
  1231.      * computing the number of fs blocks needed by the first
  1232.      * cache block.
  1233.      */
  1234.     blockPtr = (Fscache_Block *) List_First(&segLayoutDataPtr->blockList);
  1235.     blocksNeeded = LfsBytesToBlocks(lfsPtr, blockPtr->blockSize);
  1236.  
  1237.     LIST_FORALL(&segLayoutDataPtr->blockList, (List_Links *) blockPtr) {
  1238.         int bytesUsed;
  1239.         int modTime;
  1240.        /*
  1241.         * Make sure there is enough room for both the data blocks in 
  1242.         * the data region and the block number in the summary region.
  1243.         */
  1244.        summaryPtr = LfsSegGrowSummary(segPtr, blocksNeeded, sizeof(int));
  1245.        if (summaryPtr == (char *) NIL) {
  1246.            full = TRUE;
  1247.            break;
  1248.        }
  1249.        /*
  1250.         * Yes there is; add the cache block and fill in the summary region.
  1251.         * Update the LfsFileLayoutSummary to reflect the data block being
  1252.         * added and the number of fs blocks used.
  1253.         */
  1254.        *(int *) summaryPtr = blockPtr->blockNum;
  1255.        summaryPtr += sizeof(int);
  1256.        LfsSegSetSummaryPtr(segPtr,summaryPtr);
  1257.        bufferPtr = LfsSegAddDataBuffer(segPtr, blocksNeeded, 
  1258.                 blockPtr->blockAddr, (ClientData) blockPtr);
  1259.  
  1260.        fileSumPtr->numDataBlocks++; 
  1261.        fileSumPtr->numBlocks += blocksNeeded;
  1262.  
  1263.        /*
  1264.         * Update the index for this file and increment the 
  1265.         * active bytes of the segment by the size of the cache
  1266.         * block rounded to file system blocks.
  1267.         */
  1268.        bytesUsed = LfsBlocksToBytes(lfsPtr,
  1269.             LfsBytesToBlocks(lfsPtr, blockPtr->blockSize));
  1270.        status = LfsFile_SetIndex(
  1271.                 (Fsio_FileIOHandle *)(cacheInfoPtr->hdrPtr), 
  1272.                 blockPtr->blockNum, bytesUsed, 
  1273.                 FSCACHE_CANT_BLOCK,
  1274.                 LfsSegDiskAddress(segPtr, bufferPtr));
  1275.        if (status != SUCCESS) {
  1276.          blockPtr->flags |= FSCACHE_BLOCK_DIRTY;
  1277.          LfsError(lfsPtr, status, "Can't update file index");
  1278.        }
  1279.        segPtr->activeBytes += bytesUsed;
  1280.        /*
  1281.         * For ASPLOS measurements.  Remove when done.  -Mary 2/15/92.
  1282.         */
  1283.        if (Lfs_DoASPLOSStats) {
  1284.            LFS_STATS_ADD(lfsPtr->stats.log.fileBytesWritten, bytesUsed);
  1285.            if (token == CLEANING_TOKEN) {
  1286.            LFS_STATS_ADD(lfsPtr->stats.log.cleanFileBytesWritten,
  1287.                bytesUsed);
  1288.         }
  1289.        }
  1290.         
  1291.        /*
  1292.         * Update the modtime time of the segment to reflect this block
  1293.         * if it is under than the rest.
  1294.         */
  1295.        modTime = descPtr->dataModifyTime;
  1296.        if (segPtr->timeOfLastWrite < modTime) {
  1297.            segPtr->timeOfLastWrite = modTime;
  1298.        }
  1299.        /*
  1300.         * Any blocks after the first one must be of FS_BLOCK_SIZE 
  1301.         * size.
  1302.         */
  1303.        blocksNeeded = lfsBlocksPerBlock;
  1304.        /*
  1305.         * Stop going down the list when we get to the first block we
  1306.         * pushed on.
  1307.         */
  1308.        if (blockPtr == firstBlockPtr) {
  1309.         break;
  1310.        }
  1311.     } 
  1312.     if (full) { 
  1313.         while(1) {
  1314.         Fscache_Block *nextBlockPtr;
  1315.         /*
  1316.          * We're not able to place all the blocks, return to the cache
  1317.          * all blocks we couldn't place.
  1318.          */
  1319.         LFS_STATS_INC(lfsPtr->stats.layout.dirtyBlocksReturned);
  1320.         nextBlockPtr = (Fscache_Block *) 
  1321.                 List_Next((List_Links *)blockPtr);
  1322.         List_Remove((List_Links *) blockPtr);
  1323.         if (token == CLEANING_TOKEN) {
  1324.             /* 
  1325.              * Reset the flag marking this block as being cleaned
  1326.              * before returning it to the cache.
  1327.              */
  1328.             blockPtr->flags |= FSCACHE_BLOCK_BEING_CLEANED;
  1329.         }
  1330.         Fscache_ReturnDirtyBlock(blockPtr, GEN_EINTR);
  1331.         if (blockPtr == firstBlockPtr) {
  1332.             break;
  1333.         }
  1334.         blockPtr = nextBlockPtr;
  1335.         } 
  1336.     }
  1337.     }
  1338.     if (full) { 
  1339.      return full;
  1340.     }
  1341.    /*
  1342.     * If the segment we are adding has no slots open in the descriptor
  1343.     * block try to allocate a new descriptor block.
  1344.     */
  1345.     if (segLayoutDataPtr->numDescSlotsLeft == 0) {
  1346.     LfsFileLayoutDesc    *descSumPtr;
  1347.     int        descBlocks, descBytes;
  1348.  
  1349.     /*
  1350.      * Compute the size and add the descriptor block.
  1351.      */
  1352.     descBytes = layoutPtr->params.descPerBlock * sizeof(LfsFileDescriptor);
  1353.     descBlocks = LfsBytesToBlocks(lfsPtr, descBytes);
  1354.  
  1355.     summaryPtr = LfsSegGrowSummary(segPtr, descBlocks, 
  1356.                         sizeof(LfsFileLayoutDesc));
  1357.     if (summaryPtr != (char *) NIL) {
  1358.         LfsSegElement *descBufferPtr;
  1359.         char      *descMemPtr;
  1360.         ClientData    clientData;
  1361.         /*
  1362.          * Allocate space for the descriptor block and fill in a
  1363.          * summary block describing it. 
  1364.          */
  1365.         descBufferPtr = LfsSegAddDataBuffer(segPtr, descBlocks,
  1366.                         (char *) NIL, (ClientData) NIL);
  1367.         segLayoutDataPtr->numDescSlotsLeft = layoutPtr->params.descPerBlock;
  1368.         segLayoutDataPtr->descDiskAddr = 
  1369.                 LfsSegDiskAddress(segPtr, descBufferPtr);
  1370.         descMemPtr = (char *) NIL;
  1371.         clientData = LfsDescCacheBlockInit(lfsPtr, 
  1372.                 segLayoutDataPtr->descDiskAddr, TRUE, 
  1373.                 &descMemPtr);
  1374.         segLayoutDataPtr->descBlockPtr = (LfsFileDescriptor *) descMemPtr;
  1375.         descBufferPtr->address = descMemPtr;
  1376.         descBufferPtr->clientData = clientData;
  1377.  
  1378.         descSumPtr = (LfsFileLayoutDesc *) summaryPtr;
  1379.  
  1380.         descSumPtr->blockType =  LFS_FILE_LAYOUT_DESC;
  1381.         descSumPtr->numBlocks = descBlocks;
  1382.  
  1383.         summaryPtr += sizeof(LfsFileLayoutDesc);
  1384.         LfsSegSetSummaryPtr(segPtr, summaryPtr);
  1385.  
  1386.     }
  1387.     }
  1388.     /*
  1389.      * If we successfully place this file in the segment add the descriptor
  1390.      * to the descriptor block. If this is no room then mark the segment 
  1391.      * as full.
  1392.      */
  1393.     if (segLayoutDataPtr->numDescSlotsLeft > 0) {
  1394.       /*
  1395.        * XXX - need to do this under lock. 
  1396.        */
  1397.       LFS_STATS_INC(lfsPtr->stats.layout.descWritten);
  1398.       cacheInfoPtr->flags &= ~FSCACHE_FILE_DESC_DIRTY;
  1399.       descPtr->flags &= ~FSDM_FD_DIRTY;    
  1400.       bcopy((char *) descPtr, 
  1401.         (char *)&(segLayoutDataPtr->descBlockPtr->common),
  1402.         (int)sizeof(*descPtr));
  1403.       segLayoutDataPtr->descBlockPtr->fileNumber = 
  1404.               cacheInfoPtr->hdrPtr->fileID.minor;
  1405.       status = LfsDescMapSetDiskAddr(lfsPtr, 
  1406.             (int)segLayoutDataPtr->descBlockPtr->fileNumber, 
  1407.             segLayoutDataPtr->descDiskAddr);
  1408.       if (status != SUCCESS) {
  1409.           LfsError(lfsPtr, status, "Can't update descriptor map.\n");
  1410.       }
  1411.       segLayoutDataPtr->descBlockPtr++;
  1412.       segLayoutDataPtr->numDescSlotsLeft--;
  1413.       /*
  1414.        * This stat is for ASPLOS.  Remove it when that's all over.
  1415.        * Mary  2/15/92.
  1416.        */
  1417.       if (Lfs_DoASPLOSStats) {
  1418.           LFS_STATS_ADD(lfsPtr->stats.layout.descLayoutBytes,
  1419.               sizeof(LfsFileDescriptor));
  1420.       }
  1421.       segPtr->activeBytes += sizeof(LfsFileDescriptor);
  1422.      } else {
  1423.      full = TRUE;
  1424.      }
  1425.      return full;
  1426. }
  1427.  
  1428.  
  1429. /*
  1430.  * ----------------------------------------------------------------------------
  1431.  *
  1432.  * BlockMatch --
  1433.  *
  1434.  *     Cache backend block type match.  
  1435.  *
  1436.  * Results:
  1437.  *    TRUE.
  1438.  *
  1439.  * Side effects:
  1440.  *
  1441.  * ----------------------------------------------------------------------------
  1442.  */
  1443. /*ARGSUSED*/
  1444. static Boolean
  1445. BlockMatch(blockPtr, clientData)
  1446.     Fscache_Block *blockPtr;
  1447.     ClientData       clientData;
  1448. {
  1449.     int blockLevel = ((int) clientData) & 0xffff;
  1450.     int token = ((int) clientData) >> 16;
  1451.  
  1452.     /*
  1453.      * The match fails if:
  1454.      * a) We want a data block and the block is an indirect block.
  1455.      *      or
  1456.      * b) We want an indirect block and the blocks is a data or
  1457.      *      double indirect block.
  1458.      *        or
  1459.      * c) We want a double indirect block and don't get it.
  1460.      */
  1461.     if ( ((blockLevel == LFS_FILE_LAYOUT_DATA) && (blockPtr->blockNum < 0)) ||
  1462.      ((blockLevel == LFS_FILE_LAYOUT_INDIRECT) && 
  1463.         ((blockPtr->blockNum >= 0) || (blockPtr->blockNum == -2))) || 
  1464.      ((blockLevel == LFS_FILE_LAYOUT_DBL_INDIRECT) && 
  1465.          (blockPtr->blockNum != -2))) { 
  1466.     return FALSE;
  1467.     } 
  1468.  
  1469.     if (token == CLEANING_TOKEN) {
  1470.     return ((blockPtr->flags & FSCACHE_BLOCK_BEING_CLEANED) != 0);
  1471.     } else {
  1472.     return TRUE;
  1473.     }
  1474. }
  1475.  
  1476.  
  1477. /*
  1478.  * ----------------------------------------------------------------------------
  1479.  *
  1480.  * LfsFileMatch --
  1481.  *
  1482.  *     Cache backend file match for LFS.
  1483.  *
  1484.  * Results:
  1485.  *    TRUE.
  1486.  *
  1487.  * Side effects:
  1488.  *
  1489.  * ----------------------------------------------------------------------------
  1490.  */
  1491. /*ARGSUSED*/
  1492. Boolean
  1493. LfsFileMatch(cacheInfoPtr, clientData)
  1494.     Fscache_FileInfo *cacheInfoPtr;
  1495.     ClientData    clientData;
  1496. {
  1497.     register int token = (int) clientData;
  1498.  
  1499.     if ((token < 0) || (cacheInfoPtr->hdrPtr->fileID.minor < 0)) {
  1500.     return  (cacheInfoPtr->hdrPtr->fileID.minor == token);
  1501.     }
  1502.     if (token == WRITEBACK_TOKEN) { 
  1503.     return ((cacheInfoPtr->flags & FSCACHE_FILE_BEING_CLEANED) == 0);
  1504.     } 
  1505.     if (token == CLEANING_TOKEN) {
  1506.     return ((cacheInfoPtr->flags & FSCACHE_FILE_BEING_CLEANED) != 0);
  1507.     } 
  1508.     /*
  1509.      * Assume CHECKPOINT_TOKEN token.
  1510.      */
  1511.     return TRUE;
  1512. }
  1513. #undef LOCKPTR
  1514. #define LOCKPTR &lfsPtr->logLock
  1515.  
  1516. /*
  1517.  *----------------------------------------------------------------------
  1518.  *
  1519.  * LfsDirLogEntryAlloc --
  1520.  *
  1521.  *    Allocate a directory log entry for a directory change operation.
  1522.  *    NOTE: This routines assumes the callers has LOCKPTR held.
  1523.  *
  1524.  * Results:
  1525.  *    A pointer to the allocated LfsDirOpLogEntry structure.
  1526.  *
  1527.  * Side effects:
  1528.  *    None.
  1529.  *
  1530.  *----------------------------------------------------------------------
  1531.  */
  1532.  
  1533. LfsDirOpLogEntry *
  1534. LfsDirLogEntryAlloc(lfsPtr, entrySize, logSeqNum, foundPtr)
  1535.     Lfs        *lfsPtr;    /* LFS file system to allocate log entry for. */
  1536.     int        entrySize;    /* Size of log entry in bytes. */
  1537.     int        logSeqNum;    /* Log sequence number of entry. (-1) if new
  1538.                  * entry is needed. */
  1539.     Boolean    *foundPtr;    /* TRUE if logSeqNum award was found. */
  1540. {
  1541.     LfsDirLog *dirLogPtr = &lfsPtr->dirLog;
  1542.     LfsDirOpLogEntry *entryPtr;
  1543.  
  1544.     if (logSeqNum != -1) {
  1545.     LFS_STATS_INC(lfsPtr->stats.dirlog.entryAllocOld);
  1546.     } else {
  1547.     LFS_STATS_INC(lfsPtr->stats.dirlog.entryAllocNew);
  1548.     }
  1549.     /*
  1550.      * Wait until we are no longer writing or laying out blocks.
  1551.      */
  1552.     while (dirLogPtr->paused) {
  1553.     LFS_STATS_INC(lfsPtr->stats.dirlog.entryAllocWaits);
  1554.     Sync_Wait(&dirLogPtr->logPausedWait, FALSE);
  1555.     }
  1556.     /*
  1557.      * If the caller wants a brand new log record or the specified 
  1558.      * log record has been flushed from memory.
  1559.      */
  1560.     entryPtr = (logSeqNum != -1) ? FindLogEntry(lfsPtr, logSeqNum) : 
  1561.                    (LfsDirOpLogEntry *) NIL;
  1562.     if (entryPtr == (LfsDirOpLogEntry *) NIL) {
  1563.     if (entrySize > dirLogPtr->bytesLeftInBlock) {
  1564.         LFS_STATS_INC(lfsPtr->stats.dirlog.newLogBlock);
  1565.         NewDirLogBlock(lfsPtr);
  1566.     }
  1567.     entryPtr = (LfsDirOpLogEntry *) dirLogPtr->nextBytePtr;
  1568.     entryPtr->hdr.logSeqNum = dirLogPtr->nextLogSeqNum++;
  1569.     dirLogPtr->nextBytePtr += entrySize;
  1570.     dirLogPtr->bytesLeftInBlock -= entrySize;
  1571.     dirLogPtr->curBlockHdrPtr->size += entrySize;
  1572.     *foundPtr = FALSE;
  1573.     return entryPtr;
  1574.     } 
  1575.     /*
  1576.      * Called wanted a previous entry that is still in memory.
  1577.      */
  1578.     LFS_STATS_INC(lfsPtr->stats.dirlog.entryAllocFound);
  1579.     *foundPtr = TRUE;
  1580.     return entryPtr;
  1581. }
  1582.  
  1583. /*
  1584.  *----------------------------------------------------------------------
  1585.  *
  1586.  * DirLogInit --
  1587.  *
  1588.  *    Initialize the directory change log for this LFS file system.
  1589.  *
  1590.  * Results:
  1591.  *    None.
  1592.  *
  1593.  * Side effects:
  1594.  *    None.
  1595.  *
  1596.  *----------------------------------------------------------------------
  1597.  */
  1598.  
  1599. static void
  1600. DirLogInit(lfsPtr)
  1601.     Lfs    *lfsPtr;    /* File system to initialize dir log for. */
  1602. {
  1603.     LfsDirLog *dirLogPtr = &lfsPtr->dirLog;
  1604.     Fscache_Attributes        attr;
  1605.  
  1606.     dirLogPtr->nextLogSeqNum = 0;
  1607.     dirLogPtr->curBlockHdrPtr = (LfsDirOpLogBlockHdr *) NIL;
  1608.     dirLogPtr->nextBytePtr = (char *) NIL;
  1609.     dirLogPtr->bytesLeftInBlock = 0;
  1610.     List_Init(&dirLogPtr->activeListHdr);
  1611.     List_Init(&dirLogPtr->writingListHdr);
  1612.     /*
  1613.      * Initialize the file handle used to create descriptor blocks under
  1614.      */
  1615.     bzero((char *)(&dirLogPtr->handle),sizeof(dirLogPtr->handle));
  1616.     dirLogPtr->handle.hdr.fileID.major = lfsPtr->domainPtr->domainNumber;
  1617.     dirLogPtr->handle.hdr.fileID.minor = -1024;
  1618.     dirLogPtr->handle.hdr.fileID.type = FSIO_LCL_FILE_STREAM;
  1619.     dirLogPtr->handle.descPtr = (Fsdm_FileDescriptor *)NIL;
  1620.  
  1621.     bzero((Address)&attr, sizeof(attr));
  1622.     attr.lastByte = 0x7fffffff;
  1623.     Fscache_FileInfoInit(&dirLogPtr->handle.cacheInfo,
  1624.             (Fs_HandleHeader *) &dirLogPtr->handle,
  1625.             0, TRUE, &attr, lfsPtr->domainPtr->backendPtr);
  1626.     dirLogPtr->leastCachedSeqNum = 0;
  1627.     dirLogPtr->paused = FALSE;
  1628. }
  1629.  
  1630. /*
  1631.  *----------------------------------------------------------------------
  1632.  *
  1633.  * DirLogDestory --
  1634.  *
  1635.  *    Free up the directory change log for this LFS file system.
  1636.  *
  1637.  * Results:
  1638.  *    None.
  1639.  *
  1640.  * Side effects:
  1641.  *    None.
  1642.  *
  1643.  *----------------------------------------------------------------------
  1644.  */
  1645.  
  1646. static void
  1647. DirLogDestory(lfsPtr)
  1648.     Lfs    *lfsPtr;    /* File system to initialize dir log for. */
  1649. {
  1650.     LfsDirLog *dirLogPtr = &lfsPtr->dirLog;
  1651.  
  1652.     if (!List_IsEmpty(&dirLogPtr->activeListHdr) || 
  1653.     !List_IsEmpty(&dirLogPtr->writingListHdr) ||
  1654.     (dirLogPtr->curBlockHdrPtr !=  (LfsDirOpLogBlockHdr *) NIL)) {
  1655.     LfsError(lfsPtr, FAILURE,
  1656.         "DirLogDestory - directory log still active\n");
  1657.     return;
  1658.     }
  1659.  
  1660.     Fscache_FileInvalidate(&dirLogPtr->handle.cacheInfo, 0, FSCACHE_LAST_BLOCK);
  1661. }
  1662.  
  1663. /*
  1664.  *----------------------------------------------------------------------
  1665.  *
  1666.  * NewDirLogBlock --
  1667.  *
  1668.  *    Add a new directory change log blocks to the currently going log.
  1669.  *    This routine should be called when a log entry needs to be added 
  1670.  *    yet doesn't fit.
  1671.  *
  1672.  * Results:
  1673.  *    None.
  1674.  *
  1675.  * Side effects:
  1676.  *    Fscache_Block blocks fetched from cache and put on activeList.
  1677.  *
  1678.  *----------------------------------------------------------------------
  1679.  */
  1680. static void
  1681. NewDirLogBlock(lfsPtr)
  1682.     Lfs    *lfsPtr;    /* File system of add dir log block for. */
  1683. {
  1684.     LfsDirLog *dirLogPtr = &lfsPtr->dirLog;
  1685.     LfsDirOpLogBlockHdr *curBlockHdrPtr;
  1686.     Fscache_Block    *blockPtr;
  1687.     Boolean    found;
  1688.  
  1689.  
  1690.    Fscache_FetchBlock(&dirLogPtr->handle.cacheInfo,
  1691.         dirLogPtr->nextLogSeqNum, (FSCACHE_DESC_BLOCK|FSCACHE_DONT_BLOCK|FSCACHE_CANT_BLOCK),
  1692.             &blockPtr, &found);
  1693.    if (blockPtr == (Fscache_Block *) NIL) {
  1694.     LfsError(lfsPtr, FAILURE, "No space for dir log block in cache");
  1695.     return;
  1696.    }
  1697.    if (found) {
  1698.     LfsError(lfsPtr, FAILURE, "Found dir log block in cache");
  1699.    }
  1700.    curBlockHdrPtr = dirLogPtr->curBlockHdrPtr =  
  1701.                 (LfsDirOpLogBlockHdr *) blockPtr->blockAddr;
  1702.  
  1703.    curBlockHdrPtr->magic = LFS_DIROP_LOG_MAGIC;
  1704.    curBlockHdrPtr->size = sizeof(LfsDirOpLogBlockHdr);
  1705.    curBlockHdrPtr->nextLogBlock = 0;
  1706.    curBlockHdrPtr->reserved = 0;
  1707.    dirLogPtr->nextBytePtr = (char *) (curBlockHdrPtr+1);
  1708.    dirLogPtr->bytesLeftInBlock = FS_BLOCK_SIZE - sizeof(LfsDirOpLogBlockHdr);
  1709.    List_Insert((List_Links *) blockPtr, LIST_ATREAR(&dirLogPtr->activeListHdr));
  1710. }
  1711.  
  1712. /*
  1713.  *----------------------------------------------------------------------
  1714.  *
  1715.  * FindLogEntry --
  1716.  *
  1717.  *    Find a directory change operation log entry in the in memory 
  1718.  *    log buffers.
  1719.  *
  1720.  * Results:
  1721.  *    None.
  1722.  *
  1723.  * Side effects:
  1724.  *    None.
  1725.  *
  1726.  *----------------------------------------------------------------------
  1727.  */
  1728. static LfsDirOpLogEntry *
  1729. FindLogEntry(lfsPtr, logSeqNum)
  1730.     Lfs    *lfsPtr;    /* File system containing directory log. */
  1731.     int    logSeqNum;    /* Log sequent number we are looking for. */
  1732. {
  1733.     LfsDirLog *dirLogPtr = &lfsPtr->dirLog;
  1734.     Fscache_Block *blockPtr;
  1735.     LfsDirOpLogEntry *entryPtr, *limitPtr;
  1736.     LfsDirOpLogBlockHdr *curBlockHdrPtr;
  1737.  
  1738.     if (logSeqNum < dirLogPtr->leastCachedSeqNum) {
  1739.     LFS_STATS_INC(lfsPtr->stats.dirlog.fastFindFail);
  1740.     return (LfsDirOpLogEntry *) NIL;
  1741.     }
  1742.  
  1743.     blockPtr = (Fscache_Block *) List_Last(&dirLogPtr->activeListHdr);
  1744.     while(1) {  
  1745.     if (blockPtr->blockNum <= logSeqNum) {
  1746.         curBlockHdrPtr = (LfsDirOpLogBlockHdr *) blockPtr->blockAddr;
  1747.         limitPtr = (LfsDirOpLogEntry *) 
  1748.                 (blockPtr->blockAddr + curBlockHdrPtr->size);
  1749.         entryPtr = (LfsDirOpLogEntry *) (curBlockHdrPtr + 1);
  1750.         while (entryPtr < limitPtr) { 
  1751.         LFS_STATS_INC(lfsPtr->stats.dirlog.findEntrySearch);
  1752.         if (entryPtr->hdr.logSeqNum == logSeqNum) {
  1753.             return entryPtr;
  1754.         }
  1755.         entryPtr = (LfsDirOpLogEntry *) 
  1756.                 (((char *) entryPtr) + 
  1757.                     LFS_DIR_OP_LOG_ENTRY_SIZE(entryPtr));
  1758.         }
  1759.     }
  1760.     if (blockPtr == (Fscache_Block *)List_First(&dirLogPtr->activeListHdr)){
  1761.         LfsError(lfsPtr, FAILURE, "Can't fine log entry in log.\n");
  1762.         break;
  1763.     }
  1764.     blockPtr = (Fscache_Block *) List_Prev((List_Links *) blockPtr);
  1765.     }
  1766.  
  1767.     return (LfsDirOpLogEntry *) NIL;
  1768.  
  1769. }
  1770.  
  1771. /*
  1772.  *----------------------------------------------------------------------
  1773.  *
  1774.  * AddDirLogBlocks --
  1775.  *
  1776.  *    Add a directory change log blocks to a segment to be written.
  1777.  *
  1778.  * Results:
  1779.  *    TRUE if we filled up the segment. False otherwise.
  1780.  *
  1781.  * Side effects:
  1782.  *    Fscache_Blocks are moved from the activeList to the writingList.
  1783.  *
  1784.  *----------------------------------------------------------------------
  1785.  */
  1786. static Boolean
  1787. AddDirLogBlocks(lfsPtr, segPtr, segLayoutDataPtr, currentOp)
  1788.     Lfs        *lfsPtr;    /* File system. */
  1789.     LfsSeg    *segPtr;    /* Segment to place data. */
  1790.     FileSegLayout  *segLayoutDataPtr; /* Layout data of segment. */
  1791.     int        currentOp;    /* ASPLOS only - remove when done.
  1792.                  * Mary 2/15/92.
  1793.                  * Current operation (cleaning, etc.). */
  1794. {
  1795.     LfsDirLog *dirLogPtr = &lfsPtr->dirLog;
  1796.     Fscache_Block *blockPtr;
  1797.     LfsDirOpLogBlockHdr *curBlockHdrPtr;
  1798.     LfsFileLayoutLog  *sumPtr;
  1799.     int        blocks;
  1800.     LOCK_MONITOR;
  1801.     sumPtr = (LfsFileLayoutLog *) NIL;
  1802.     while (!List_IsEmpty(&dirLogPtr->activeListHdr)) {
  1803.        LfsSegElement *elementPtr;
  1804.        blockPtr = (Fscache_Block *) List_First(&dirLogPtr->activeListHdr);
  1805.        curBlockHdrPtr = (LfsDirOpLogBlockHdr *) blockPtr->blockAddr;
  1806.        blocks = LfsBytesToBlocks(lfsPtr, curBlockHdrPtr->size);
  1807.        if (sumPtr == (LfsFileLayoutLog *) NIL) {
  1808.            sumPtr = (LfsFileLayoutLog *) LfsSegGrowSummary(segPtr, blocks, 
  1809.                 sizeof(LfsFileLayoutLog));
  1810.            if (sumPtr == (LfsFileLayoutLog *) NIL) {
  1811.             UNLOCK_MONITOR;
  1812.             return TRUE;
  1813.            }
  1814.            sumPtr->blockType = LFS_FILE_LAYOUT_DIR_LOG;
  1815.            sumPtr->numDataBlocks = 0;
  1816.            sumPtr->numBlocks = 0; /* Filled in later. */
  1817.            sumPtr->reserved = 0;
  1818.            dirLogPtr->paused = TRUE;
  1819.        }
  1820.        LfsSegSetSummaryPtr(segPtr, (char *) (sumPtr+1));
  1821.        elementPtr = LfsSegAddDataBuffer(segPtr, blocks, 
  1822.                 blockPtr->blockAddr, (ClientData) blockPtr);
  1823.        if (elementPtr == (LfsSegElement *) NIL) {
  1824.             /*
  1825.          * Could not fit block in segment.
  1826.          */
  1827.         UNLOCK_MONITOR;
  1828.         return TRUE;
  1829.         }
  1830.        sumPtr->numDataBlocks++; 
  1831.        sumPtr->numBlocks += blocks;
  1832.        LFS_STATS_INC(lfsPtr->stats.dirlog.dataBlockWritten);
  1833.        LFS_STATS_ADD(lfsPtr->stats.dirlog.blockWritten, blocks);
  1834.        LFS_STATS_ADD(lfsPtr->stats.dirlog.bytesWritten, 
  1835.             curBlockHdrPtr->size);
  1836.        /*
  1837.         * ASPLOS measurements - remove when done.  -Mary 2/15/92.
  1838.         */
  1839.        if (currentOp == CLEANING_TOKEN && Lfs_DoASPLOSStats) {
  1840.             LFS_STATS_ADD(lfsPtr->stats.dirlog.cleaningBytesWritten,
  1841.             curBlockHdrPtr->size);
  1842.         }
  1843.  
  1844.        List_Move((List_Links *) blockPtr, &segLayoutDataPtr->dirLogListHdr);
  1845.        if  (curBlockHdrPtr == dirLogPtr->curBlockHdrPtr) {
  1846.         dirLogPtr->curBlockHdrPtr = (LfsDirOpLogBlockHdr *) NIL;
  1847.         dirLogPtr->nextBytePtr = (char *) NIL;
  1848.         dirLogPtr->bytesLeftInBlock = 0;
  1849.        }
  1850.     }
  1851.     UNLOCK_MONITOR;
  1852.     return FALSE;
  1853.  
  1854. }
  1855.  
  1856. /*
  1857.  *----------------------------------------------------------------------
  1858.  *
  1859.  * FreeDirLogBlocks --
  1860.  *
  1861.  *    Free directory log blocks that were written to disk.
  1862.  *
  1863.  * Results:
  1864.  *    None.
  1865.  *
  1866.  * Side effects:
  1867.  *    Fscache_Blocks on writingList are deleted from cache.
  1868.  *
  1869.  *----------------------------------------------------------------------
  1870.  */
  1871. static void
  1872. FreeDirLogBlocks(lfsPtr, segPtr, segLayoutDataPtr)
  1873.     Lfs        *lfsPtr;    /* File system. */
  1874.     LfsSeg    *segPtr;    /* Segment to place data. */
  1875.     FileSegLayout  *segLayoutDataPtr; /* Layout data of segment. */
  1876. {
  1877.     LfsDirLog *dirLogPtr = &lfsPtr->dirLog;
  1878.     Fscache_Block *blockPtr;
  1879.  
  1880.     LOCK_MONITOR;
  1881.     dirLogPtr->leastCachedSeqNum = dirLogPtr->nextLogSeqNum;
  1882.     while (!List_IsEmpty(&segLayoutDataPtr->dirLogListHdr)) {
  1883.     blockPtr = (Fscache_Block *) 
  1884.             List_First(&segLayoutDataPtr->dirLogListHdr);
  1885.     List_Remove((List_Links *)blockPtr);
  1886.     Fscache_UnlockBlock(blockPtr, (time_t)0, -1, 0, FSCACHE_DELETE_BLOCK);
  1887.     }
  1888.     dirLogPtr->paused = FALSE;
  1889.     Sync_Broadcast(&dirLogPtr->logPausedWait);
  1890.     UNLOCK_MONITOR;
  1891. }
  1892.  
  1893.  
  1894.